package cn.zifangsky.jvm.part2.reference;

import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.concurrent.CountDownLatch;

/**
 * 弱引用
 *
 * @author zifangsky
 * @date 2020/7/11
 * @since 1.0.0
 */
public class WeakRefQueueTest {
    public static ReferenceQueue<User> weakQueue = null;
    public static CountDownLatch latch = new CountDownLatch(1);

    public static void main(String[] args) throws InterruptedException {
        //添加一个后台监控引用队列的线程
        Thread t = new CheckRefQueue();
        t.setDaemon(true);
        t.start();

        User u = new User(1, "admin");
        //初始化引用队列
        weakQueue = new ReferenceQueue<>();
        UserWeakReference userWeakRef = new UserWeakReference(u, weakQueue);
        //去除强引用
        u = null;

        System.out.println(userWeakRef.get());
        System.gc();
        //不管当前内存空间足够与否，都会回收它的内存
        System.out.println("第一次GC后：" + userWeakRef.get());

        latch.await();
    }

    /**
     * 监控引用队列的线程
     */
    public static class CheckRefQueue extends Thread {
        @Override
        public void run() {
            while (true) {
                if (weakQueue != null) {
                    UserWeakReference obj = null;
                    try {
                        obj = (UserWeakReference) weakQueue.remove();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    if (obj != null) {
                        System.out.println("user id " + obj.userId + " was deleted");
                        latch.countDown();
                    }
                }
            }
        }
    }

    public static class User {
        private int id;
        private String name;
        private byte[] arr;

        public User(int id, String name) {
            this.id = id;
            this.name = name;
            //默认申请一个占4M内存的数组
            this.arr = new byte[1024 * 1024 * 4];
        }

        public int getId() {
            return id;
        }

        public String getName() {
            return name;
        }

        @Override
        public String toString() {
            return "[id=" + String.valueOf(id) + ", name=" + name + "]";
        }
    }

    public static class UserWeakReference extends WeakReference<User> {
        private int userId;

        public UserWeakReference(User referent, ReferenceQueue<? super User> q) {
            super(referent, q);
            userId = referent.id;
        }

        public int getUserId() {
            return userId;
        }
    }
}
